﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Security;
using System.Security.Principal;
using System.Web.Profile;
using System.Configuration;
using System.Web.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Web;
using System.Web.Mvc;
using Vit.Common;
using Vit.Common.Helpers;
using Vit.Web;
using Vit.Web.Helpers;
using Vit.Web.Extensions;
using Vit.Web.Models;

namespace Vit.AdminModule.Areas.Admin.Providers
{
    public class SqlMembershipProvider : Vit.Web.Providers.IMembershipProvider
    {
        WebProvidersDb db;

        public SqlMembershipProvider(WebProvidersDb db)
        {
            this.db = db;
        }

        #region IMembershipProvider Members

        public bool Login(string account, string password, bool rememberMe)
        {
            Logout();
            if (ValidateUser(account, password))
            {
                User user = db.Users.FirstOrDefault(o => o.Account == account);
                FormsAuthentication.SetAuthCookie(account, rememberMe);
                user.LastLoginTime = DateTime.Now;
                user.LastActiveTime = DateTime.Now;
                db.SaveChanges();
                PortalContext.Current.User = user;
                return true;
            }
            return false;
        }
        public void Logout()
        {
            FormsAuthentication.SignOut();
            HttpContext.Current.Session.Clear();
        }

        public bool ChangePassword(string account, string oldPassword, string newPassword)
        {
            if (ValidateUser(account, oldPassword))
            {
                User user = db.Users.FirstOrDefault(o => o.Account == account);
                user.Password = SecurityHelper.Hash(newPassword);
                db.SaveChanges();
            }
            return false;
        }

        public User CreateUser(string name, string account, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, out string error)
        {
            error = string.Empty;
            User user = new User()
            {
                Name = name,
                Account = account,
                Password = SecurityHelper.Hash(password),
                Email = email
            };

            user.Site = PortalContext.Current.Site;

            db.Users.Add(user);
            db.SaveChanges();
            return user;
        }

        public bool UpdateUser(User user)
        {
            User duser = db.Users.FirstOrDefault(o => o.Account == user.Account);
            if (user != null)
            {
                duser.Name = user.Name;
                duser.Roles = user.Roles;

                db.SaveChanges();
            }
            return true;
        }

        public bool DeleteUser(string account, bool deleteAllRelatedData)
        {
            User user = db.Users.FirstOrDefault(o => o.Account == account);
            if (user != null)
            {
                if (deleteAllRelatedData)
                {
                    db.Users.Remove(user);
                }
                else
                {
                    user.Status = (int)DataStatus.Deleted;
                }
                db.SaveChanges();
                return true;
            }
            return false;
        }

        public bool LockUser(string account)
        {
            User user = db.Users.FirstOrDefault(o => o.Account == account);
            if (user != null)
            {
                user.Status = (int)DataStatus.Locked;
                db.SaveChanges();
            }
            return false;
        }

        public bool UnlockUser(string account)
        {
            User user = db.Users.FirstOrDefault(o => o.Account == account);
            if (user != null)
            {
                user.Status = (int)DataStatus.Normal;
                db.SaveChanges();
            }
            return false;
        }

        public bool ValidateUser(string account, string password)
        {
            password = SecurityHelper.Hash(password);
            User user = db.Users.FirstOrDefault(o => o.Account == account && o.Password == password);
            return user != null;
        }

        public User GetUser(string account)
        {
            User user = db.Users.FirstOrDefault(o => o.Account == account);
            return user;
        }

        public string GetUserNameByEmail(string email)
        {
            User user = db.Users.FirstOrDefault(o => o.Email == email);
            return user == null ? string.Empty : user.Name;
        }

        public IQueryable<User> GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            totalRecords = db.Users.Count();
            var users = db.Users.OrderBy(o => o.Account).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            return users;
        }

        public int GetNumberOfUsersOnline()
        {
            return db.Users.Count(o => o.LastActiveTime >= DateTime.Now.AddMinutes(60));
        }

        public Role CreateRole(string roleName)
        {
            Role role = new Role()
            {
                Name = roleName
            };

            db.Roles.Add(role);
            db.SaveChanges();
            return role;
        }

        public bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            try
            {
                var role = db.Roles.FirstOrDefault(o => o.Name == roleName);
                if (role != null)
                {
                    db.Roles.Remove(role);
                    db.SaveChanges();
                }
                return true;
            }
            catch
            {
                if (throwOnPopulatedRole)
                    throw;
            }
            return false;
        }

        public IQueryable<Role> GetAllRoles()
        {
            return db.Roles;
        }

        public bool RoleExists(string roleName)
        {
            return db.Roles.Any(o => o.Name.ToLower() == roleName.ToLower());
        }

        public bool AccountExists(string account)
        {
            return db.Users.Any(o => o.Account.ToLower() == account.ToLower());
        }

        public bool EmailExists(string email)
        {
            return db.Users.Any(o => o.Email.ToLower() == email.ToLower());
        }

        public bool CanUserAccess(string account, string permissionUri)
        {
            var administratorAccount = ConfigurationManager.AppSettings["AdministratorAccount"];
            if (administratorAccount.Equals(account, StringComparison.OrdinalIgnoreCase))
                return true;
            var user = PortalContext.Current.User;
            if (!string.Equals(user.Account, account, StringComparison.OrdinalIgnoreCase))
                user = GetUser(account);
            if (user != null && user.Roles != null)
            {
                return user.Roles.Any(o => o.Permissions != null && o.Permissions.Any(p => Regex.IsMatch(permissionUri, p.Pattern, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace)));
            }
            return false;
        }

        public bool CanRoleAccess(string rolename, string permissionUri)
        {
            var role = db.Roles.FirstOrDefault(o => o.Name == rolename);
            if (role != null && role.Permissions != null)
            {
                return role.Permissions.Any(o => Regex.IsMatch(permissionUri, o.Pattern, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace));
            }
            return false;
        }

        #endregion

        #region IProvider Members

        public string Name
        {
            get { return "SqlMembershipProvider"; }
        }

        #endregion
    }
}